package service

import (
	"context"
	"crypto/tls"
	"fmt"
	"math/rand"
	"net/smtp"
	"strconv"
	"strings"
	"time"

	"github.com/jordan-wright/email"
	"github.com/redis/go-redis/v9"
	"sysu-giep/internal/config"
	"sysu-giep/pkg/logger"
)

// EmailService 邮箱服务
type EmailService struct {
	config *config.EmailConfig
	redis  *redis.Client
}

// NewEmailService 创建邮箱服务实例
func NewEmailService(cfg *config.EmailConfig, redis *redis.Client) *EmailService {
	return &EmailService{
		config: cfg,
		redis:  redis,
	}
}

// EmailType 邮箱类型枚举
type EmailType int

const (
	EmailTypeValidate EmailType = iota // 验证码邮件
	EmailTypeComment                   // 评论通知
	EmailTypeMessage                   // 私信通知
	EmailTypeReply                     // 回复通知
)

// SendEmailRequest 发送邮件请求
type SendEmailRequest struct {
	To      string    `json:"to" binding:"required,email"`
	Type    EmailType `json:"type"`
	Message string    `json:"message,omitempty"`
}

// SendEmailResponse 发送邮件响应
type SendEmailResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
	VCode   string `json:"vcode,omitempty"`
}

// generateVCode 生成6位验证码
func (s *EmailService) generateVCode() string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	vcode := ""
	for i := 0; i < 6; i++ {
		vcode += strconv.Itoa(r.Intn(10))
	}
	return vcode
}

// saveVCode 保存验证码到Redis
func (s *EmailService) saveVCode(vcode, receiver string) error {
	ctx := context.Background()

	// 检查Redis连接
	if s.redis == nil {
		return fmt.Errorf("Redis客户端未初始化")
	}

	// 检查是否已存在验证码，如果存在则删除
	_, err := s.redis.Get(ctx, receiver).Result()
	if err == nil {
		s.redis.Del(ctx, receiver)
	}

	// 保存新验证码，5分钟过期
	return s.redis.Set(ctx, receiver, vcode, 5*time.Minute).Err()
}

// getVCode 从Redis获取验证码
func (s *EmailService) getVCode(receiver string) (string, error) {
	ctx := context.Background()

	// 检查Redis连接
	if s.redis == nil {
		return "", fmt.Errorf("Redis客户端未初始化")
	}

	return s.redis.Get(ctx, receiver).Result()
}

// SendEmail 发送邮件
func (s *EmailService) SendEmail(req *SendEmailRequest) (*SendEmailResponse, error) {
	// 验证配置
	if s.config == nil {
		return nil, fmt.Errorf("邮箱配置未初始化")
	}

	if s.config.Host == "" || s.config.Username == "" || s.config.Password == "" {
		return nil, fmt.Errorf("邮箱配置不完整")
	}

	e := email.NewEmail()

	// 设置发件人
	senderString := s.config.ValidateSender
	senderString = strings.Replace(senderString, "emailUsername", s.config.Username, -1)
	e.From = senderString

	// 设置收件人
	e.To = []string{req.To}

	var text string
	var vcode string

	switch req.Type {
	case EmailTypeValidate:
		// 验证码邮件
		e.Subject = s.config.ValidateTitle
		text = s.config.ValidateText

		// 生成验证码
		vcode = s.generateVCode()
		text = strings.Replace(text, "vcode", vcode, -1)

		// 保存验证码到Redis
		if err := s.saveVCode(vcode, req.To); err != nil {
			logger.ErrorLog("保存验证码失败", logger.Error(err))
			return nil, fmt.Errorf("保存验证码失败: %w", err)
		}

	case EmailTypeComment:
		// 评论通知
		e.Subject = "中山大学研究生院校企对接平台 - 评论通知"
		if len(req.Message) > 20 {
			req.Message = req.Message[:20] + "..."
		}
		text = fmt.Sprintf("您好，您在中山大学研究生院校企对接平台上的发帖收到一条新评论'%s'，请登录平台查阅。如需关闭邮箱通知请前往个人主页最下方关闭。", req.Message)

	case EmailTypeMessage:
		// 私信通知
		e.Subject = "中山大学研究生院校企对接平台 - 私信通知"
		text = "您好，您在中山大学研究生院校企对接平台上收到一条新私信，请登录平台查阅。如需关闭邮箱通知请前往个人主页最下方关闭。"

	case EmailTypeReply:
		// 回复通知
		e.Subject = "中山大学研究生院校企对接平台 - 回复通知"
		if len(req.Message) > 20 {
			req.Message = req.Message[:20] + "..."
		}
		text = fmt.Sprintf("您好，您在中山大学研究生院校企对接平台上收到一条新回复'%s'，请登录平台查阅。如需关闭邮箱通知请前往个人主页最下方关闭。", req.Message)

	default:
		return nil, fmt.Errorf("不支持的邮件类型")
	}

	e.Text = []byte(text)

	// 设置SMTP认证
	addr := fmt.Sprintf("%s:%d", s.config.Host, s.config.Port)
	auth := smtp.PlainAuth("", s.config.Username, s.config.Password, s.config.Host)

	// 发送邮件
	err := e.SendWithTLS(addr, auth, &tls.Config{ServerName: s.config.Host})
	if err != nil {
		logger.ErrorLog("发送邮件失败", logger.Error(err))
		return nil, fmt.Errorf("发送邮件失败: %w", err)
	}

	logger.Info("邮件发送成功", logger.String("to", req.To), logger.String("type", fmt.Sprintf("%d", req.Type)))

	response := &SendEmailResponse{
		Success: true,
		Message: "邮件发送成功",
	}

	// 如果是验证码邮件，返回验证码（用于测试）
	if req.Type == EmailTypeValidate {
		response.VCode = vcode
	}

	return response, nil
}

// ValidateEmailCode 验证邮箱验证码
func (s *EmailService) ValidateEmailCode(email, code string) error {
	storedCode, err := s.getVCode(email)
	if err != nil {
		return fmt.Errorf("验证码不存在或已过期")
	}

	if storedCode != code {
		return fmt.Errorf("验证码错误")
	}

	// 验证成功后删除验证码
	ctx := context.Background()
	s.redis.Del(ctx, email)

	return nil
}
